package cn.yanhu.kuwanapp.utils

import android.content.Context
import android.content.Intent
import android.content.pm.PackageInfo
import android.content.pm.PackageManager
import android.content.res.AssetFileDescriptor
import android.net.Uri
import android.os.Build
import android.text.TextUtils
import androidx.core.content.FileProvider
import java.io.File
import java.io.FileInputStream
import java.io.FileNotFoundException
import java.io.IOException
import java.math.BigInteger
import java.security.MessageDigest

/**
 * app安装工具类
 */
class AppUtils private constructor() {
    companion object {
        /**
         * 通过url获取App的全名称
         * @param context
         * @return AppName.apk
         */
        fun getAppFullName(context: Context, url: String, defaultName: String?): String {
            if (url.endsWith(".apk")) {
                return url.substring(url.lastIndexOf("/") + 1)
            }
            var filename = getAppName(context)
            if (TextUtils.isEmpty(filename)) {
                filename = defaultName
            }
            return String.format("%s.apk", filename)
        }

        /**
         * 获取包信息
         * @param context
         * @return
         * @throws PackageManager.NameNotFoundException
         */
        @Throws(PackageManager.NameNotFoundException::class)
        fun getPackageInfo(context: Context): PackageInfo {
            val packageManager = context.packageManager
            return packageManager.getPackageInfo(context.packageName, 0)
        }

        /**
         * 通过APK路径获取包信息
         * @param context
         * @param archiveFilePath
         * @return
         */
        @Throws(Exception::class)
        fun getPackageInfo(context: Context, archiveFilePath: String?): PackageInfo? {
            val packageManager = context.packageManager
            return packageManager.getPackageArchiveInfo(archiveFilePath!!, PackageManager.GET_ACTIVITIES)
        }

        /**
         * 获取App的名称
         */
        fun getAppName(context: Context): String? {
            try {
                val labelRes = getPackageInfo(context).applicationInfo.labelRes
                return context.resources.getString(labelRes)
            } catch (e: Exception) {
                e.printStackTrace()
            }
            return null
        }

        /**
         * 获取App的图标
         * @param context
         * @return
         */
        fun getAppIcon(context: Context): Int {
            try {
                return getPackageInfo(context).applicationInfo.icon
            } catch (e: Exception) {
                e.printStackTrace()
            }
            return 0
        }

        /**
         * 安装apk
         * @param context
         * @param file
         */
        fun installApk(context: Context, file: File?, authority: String?) {
            val intent = getInstallIntent(context, file, authority)
            context.startActivity(intent)
        }

        /**
         * 获取安装Intent
         * @param context
         * @param file
         * @param authority
         * @return
         */
        fun getInstallIntent(context: Context?, file: File?, authority: String?): Intent {
            val intent = Intent(Intent.ACTION_VIEW)
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
            intent.addCategory(Intent.CATEGORY_DEFAULT)
            val uriData: Uri
            val type = "application/vnd.android.package-archive"
            uriData = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
                FileProvider.getUriForFile(context!!, authority!!, file!!)
            } else {
                Uri.fromFile(file)
            }
            intent.setDataAndType(uriData, type)
            return intent
        }

        /**
         * APK是否存在
         * @param context
         * @param versionCode
         * @param file
         * @return
         * @throws Exception
         */
        @Throws(Exception::class)
        fun apkExists(context: Context, versionCode: Int, file: File?): Boolean {
            if (file != null && file.exists()) {
                val packageName = context.packageName
                val packageInfo = getPackageInfo(context, file.absolutePath)
                if (packageInfo != null && versionCode == packageInfo.versionCode) { //比对versionCode
                    val applicationInfo = packageInfo.applicationInfo
                    if (applicationInfo != null && packageName == applicationInfo.packageName) { //比对packageName
                        return true
                    }
                }
            }
            return false
        }

        /**
         * 判断文件是否存在
         * @param context
         * @param path
         * @return
         */
        fun isAndroidQFileExists(context: Context, path: String?): Boolean {
            return isAndroidQFileExists(context, File(path))
        }

        /**
         * 判断文件是否存在
         * @param context
         * @param file
         * @return
         */
        fun isAndroidQFileExists(context: Context, file: File?): Boolean {
            var descriptor: AssetFileDescriptor? = null
            val contentResolver = context.contentResolver
            try {
                val uri = Uri.fromFile(file)
                descriptor = contentResolver.openAssetFileDescriptor(uri, "r")
                if (descriptor == null) {
                    return false
                } else {
                    close(descriptor)
                }
                return true
            } catch (e: FileNotFoundException) {
            } finally {
                close(descriptor)
            }
            return false
        }

        /**
         * 校验文件MD5
         * @param file
         * @param md5
         * @return
         */
        fun checkFileMD5(file: File?, md5: String): Boolean {
            val fileMD5 = getFileMD5(file)
            return if (!TextUtils.isEmpty(md5)) {
                md5.equals(fileMD5, ignoreCase = true)
            } else false
        }

        /**
         * 获取文件MD5
         * @param file
         * @return
         */
        fun getFileMD5(file: File?): String? {
            try {
                val fis = FileInputStream(file)
                val messageDigest = MessageDigest.getInstance("MD5")
                val buffer = ByteArray(1024)
                var length: Int
                while (fis.read(buffer).also { length = it } != -1) {
                    messageDigest.update(buffer, 0, length)
                }
                val bigInteger = BigInteger(1, messageDigest.digest())
                return bigInteger.toString(16)
            } catch (e: Exception) {
                e.printStackTrace()
            }
            return null
        }

        /**
         * 关闭
         * @param descriptor
         */
        private fun close(descriptor: AssetFileDescriptor?) {
            if (descriptor != null) {
                try {
                    descriptor.close()
                } catch (e: IOException) {
                    e.printStackTrace()
                }
            }
        }
    }

    init {
        throw AssertionError()
    }
}